#ifndef __LANGUAGEPARSER_H
#define __LANGUAGEPARSER_H

#include <string>
#include <map>
#include "parser.h"
#include "numrule.h"

using namespace std;

/** Generic parser interface.
 * This one reads parsing rules from file.
 * 
 * <p>Parser files are divided into two sections: [NUMBERS] and [OPERATORS]</p>
 * 
 * <p>Numbers consist of following fields:</p>
 * <pre>  STATE,literal:semantics:NEW_STATE:flags</pre>
 * 
 * <p>Where:</p>
 * <ul>
 * <li>States "S" (Start) and "END" (force end) have special meaning.
 *   <br/>If STATE is "*", it matches any state.
 *   <br/>If NEW_STATE is missing, the state is unchanged.
 * </li>
 * <li>Literal is the prefix of the string that follows.</li>
 * <li>Semantics are either addition or multiplication. If multiplication is
 *   applied to a zero value (i.e. no value yet), it is treated as an addition
 *   instead.
 * </li>
 * <li>Flags (optional) are "free form" but no flag can be applied more than 
 *   once for any given number.
 *   <br/>Flags are separated by commas.
 *   <br/>An ! (exclamation mark) prefix means the flag must NOT be present at 
 *     the moment.
 *   <br>A - (minus sign) prefix means the flag must be removed, if present
 *   <br>The following flags have special meanings as well:
 *     <pre>
 *     must_be_first: must be in the front of the number (first token)
 *     have_minus: at the end, total must be inverted.
 *     subtotal: add the current sum to the subtotal and set current sum to zero.
 *     </pre>
 * </li>
 * </ul>
 *
 * <p>Operators are simply pairs of:</p>
 * <pre>  literal:semantics</pre>
 */
class LanguageParser : public Parser {

  private:
    /** Headers as defined above. */
    const static string SECTION_NUMBERS;
    const static string SECTION_OPERATORS;

    /** Literal length.
     * Literals are checked in a longest-first manner, resolving any prefix
     * issues. Of course, this may be insufficient, e.g. if language is not
     * LL(k) in terms of characters (where k is num_maxlen and op_maxlen, 
     * respectively). E.g. "four" is a prefix of "fourteen" but it's OK as long
     * as no valid number starts with "teen".
     *
     * By the way I *think* it is an LL(k) parser but I cannot prove it without
     * digging deep into my university notes.
     */
    size_t num_minlen, num_maxlen;
    size_t op_minlen, op_maxlen;

    /** A map of number parsing rules.
     * See above for details of rules. The key is the first field: 
     * STATE,literal
     * The NumRule contains the same key plus the rest of the rule (without the
     * leading colon) as value.
     */
    map<string, NumRule> num_rules;
    /** A map of operator parsing rules.
     * See above for details of rules. The key is the first field: literal
     * The value is the first character that comes after the colon. This means
     * that garbage afterwards is discarded.
     */
    map<string, char>    op_rules;

  public: 
    /** Default suffix for parser files. 
     * Used by Calc when it loads parsers. 
     *
     * @see Calc#loadParsers() 
     */
    const static string SUFFIX;

    /** Creates a parser from file. 
     *
     * @param path the (absolute or relative) path to parser file
     */
    LanguageParser(string path);

    /** Overridden method of base class.
     * The string is read forward only, but involves some foresight to check
     * any candidate for operators.
     *
     * @see Parser#parseNum(string, size_t &amp;)
     */
    virtual Number *parseNum(string input, size_t &pos) const;
    /** Overridden method of base class.
     * The string is read forward only. Trimming any leading whitespace, the
     * prefix is matched against any literal in the operator map.
     *
     * @see Parser#parseOp(string, size_t &amp;)
     */
    virtual char parseOp(string input, size_t &pos) const;
};

#endif
